﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using AISservice.Common;
using Common;

namespace AISservice
{
    public class RoutingService
    {
        private static Dictionary<string, Pair<MethodInfo, object>> _Method_List;
        public  static Dictionary<string, Pair<MethodInfo, object>> Method_List
        {
            get
            {
                if (_Method_List == null)
                    _Method_List = new Dictionary<string, Pair<MethodInfo, object>>();
                return _Method_List;
            }
        }

        public static void LoadAction()
        {
            Dictionary<string, string> assemblyDict = new Dictionary<string, string>();
            Assembly[] assembliesLoaded = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly asm in assembliesLoaded)
            {
                assemblyDict.Add(asm.Location, asm.FullName);
            }
            #region //加载文件
            try
            {
                //todo:将log4net放到common中去
                Log4Net.Info("path:" + System.AppDomain.CurrentDomain.BaseDirectory);
                DirectoryInfo TheFolder = new DirectoryInfo(System.AppDomain.CurrentDomain.BaseDirectory);
                //todo: load assembly时无法加载dll的config文件，要修改为xml
                //遍历文件
                foreach (FileInfo NextFile in TheFolder.GetFiles("*.dll"))
                {
                    try
                    {
                        string fullpath = NextFile.FullName;
                        if (!assemblyDict.ContainsKey(fullpath))
                        {
                            Log4Net.Info("load assembly:" + fullpath);
                            Console.WriteLine($"load assembly:{fullpath}");
                            Assembly assembly = Assembly.LoadFrom(fullpath);
                            assemblyDict.Add(fullpath, assembly.FullName);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log4Net.Error("加载业务组件错误", ex);
                    }
                }
            }
            catch (Exception ex)
            {
                Log4Net.Error("加载业务组件错误", ex);
            }
            #endregion

            #region 加载DLL中暴漏出的方法
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly asm in assemblies)
            {
                try
                {
                    object[] asmattrs = asm.GetCustomAttributes(true);
                    if (Array.Exists<object>(asmattrs, new Common.PredicateAdapter<object>(new AssemblyTrademarkAttribute("FPBAGGIO")).Predicate))
                    {
                        foreach (Type t in asm.GetTypes())
                        {
                            FindMethod(asm, t);

                        //if (t.Name.Equals("AutoRun", StringComparison.OrdinalIgnoreCase))
                        //{D:\Personalfiles\E1AIS\AISservice\AISservice\Common\
                        //    MethodInfo mi = t.GetMethod("Invoke");
                        //    if (mi != null)
                        //    {
                        //        mi.Invoke(null, null);
                        //    }
                        //}
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log4Net.Error("error while LoadAction", ex);
                }
            }
            #endregion
        }


        public static void FindMethod(Assembly asm, Type t)
        {
            object[] classattrs = t.GetCustomAttributes(typeof(HandlerContractAttribute), true);
            if (classattrs.Length == 0)
                return;
            foreach (MethodInfo method in t.GetMethods())
            {
                if (method.GetCustomAttributes(typeof(MethodOperationAttribute), true).Length == 0)
                    continue;
                string key = t.Name; //((HandlerContractAttribute)classattrs[0]).Name;
                object instance = asm.CreateInstance(t.FullName);
                RoutingService.Method_List.Add(key + "." + method.Name, new Pair<MethodInfo, object>(method, instance));
                Log4Net.Info(string.Format("已加载 Action {0}", key + "." + method.Name));
                Console.WriteLine(string.Format("已加载 Action {0}", key + "." + method.Name));
            }
        }



        //程序集名称
        private string _assname = string.Empty;
        //类名称
        private string _classname = string.Empty;
        //程序集DLL路径
        private string _assPath = string.Empty;

        public RoutingService(string assblyname, string classname)
        {
            this._assname = assblyname;
            this._classname = classname;
            _assPath = System.IO.Path.GetTempPath() + _assname + ".dll";
        }

        private static Hashtable objcache;
        public static Hashtable ObjCache
        {
            get
            {
                if (objcache == null)
                {
                    objcache = new Hashtable();
                }
                return objcache;
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="methodname"></param>
        /// <returns></returns>
        public object ExecuteMethod(string methodname)
        {
            return ExecuteMethod(methodname, null);
        }
        public object ExecuteMethod(string methodname, params object[] param)
        {
            Assembly asm = (Assembly)ObjCache[_assname];
            if (asm == null)
            {
                asm = CreateAssembly();
                if (!ObjCache.ContainsKey(_assname))
                {
                    ObjCache.Add(_assname, asm);
                }
            }
            Type type = asm.GetType(_classname);
            object instance = asm.CreateInstance(_classname);
            var method = type.GetMethod(methodname);
            if (method != null)
            {
                return method.Invoke(instance, param);
            }
            else
            {
                return null;
            }
        }


        private Assembly CreateAssembly()
        {
            Assembly assb = (Assembly)ObjCache[_assname];
            if (assb == null)
            {
                assb = Assembly.Load(_assname);
                ObjCache.Add(_assname, assb);
            }

            return assb;
        }
    }
}
